/*  
   File Browser for SalesForce
   Copyright (c) 2009  Daniel Jordan
  
   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License
   as published by the Free Software Foundation; either version 2
   of the License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
 */

using System;
using System.Collections.Generic;
using System.Text;
using SFFileBrowser.SForceService;
using System.Xml.Serialization;
using System.IO;

namespace SFFileBrowser
{
    internal class SForceAttachmentManager
    {
        SforceService _sforce = new SforceService();

        private bool loggedIn = false;
        private string userfullname = String.Empty;
        private string userOrganization = String.Empty;


        public SForceUsers Users { get; set; }

        public bool LoggedIn
        {
            get { return loggedIn; }
        }

        public string UserName
        {
            get { return userfullname; }
        }

        public string UserOrganization
        {
            get { return userOrganization; }
        }

        /// <summary>
        /// validates the given username, password and token
        /// </summary>
        /// <param name="username"></param>
        /// <param name="password"></param>
        /// <param name="token"></param>
        public void login(string username, string password, string token)
        {
            // Create service object
            try
            {

                // Invoke the login call and save results in LoginResult
                LoginResult lr = _sforce.login(username, password + token);
                if (!lr.passwordExpired)
                {
                    // Reset the SOAP endpoint to the returned server URL
                    _sforce.Url = lr.serverUrl;
                    // Create a new session header object
                    // Add the session ID returned from the login
                    _sforce.SessionHeaderValue = new SessionHeader();
                    _sforce.SessionHeaderValue.sessionId = lr.sessionId;
                    GetUserInfoResult userInfo = lr.userInfo;
                    if (userInfo.userId != null)
                    {
                        loggedIn = true;
                        userfullname = userInfo.userFullName;
                        userOrganization = userInfo.organizationName;
                    }
                }
                else
                {
                    Console.WriteLine("You password is expired.");
                }
            }
            catch (Exception ex)
            {
                throw new SForceAttachmentManagerException(ex.Message, ex);

            }
        }


        public string ToString(SForceAttachmentFolder folder)
        {
            XmlSerializer s = new XmlSerializer(typeof(SForceAttachmentFolder));
            StringWriter sw = new StringWriter();
            s.Serialize(sw, folder);
            string temp = sw.ToString();
            return temp;  
        }

        public SForceAttachmentFolder ToFolder(string data)
        {
            XmlSerializer s = new XmlSerializer(typeof(SForceAttachmentFolder));
            SForceAttachmentFolder folder = (SForceAttachmentFolder)s.Deserialize(new StringReader(data));
            return folder;
        }

        private Type getType(SForceObjectType type)
        {
           // if (type==SForceObjectType.Account)return typeof(SForceService.sforceobj
            return null;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="query"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        private SForceAttachmentFolders Folders(string query, SForceObjectType type)
        {
            SForceAttachmentFolders collection = new SForceAttachmentFolders();
            QueryResult result =_sforce.queryAll(query);
            
            if(result.size==0)return collection;

            for (int i = 0; i < result.records.Length; i++)
            {
                SForceAttachmentFolder folder = new SForceAttachmentFolder();
                folder.SForceObjectType = type;
                folder.Id = result.records[i].Id;
                folder.Name = result.records[i].Any[0].InnerText;  //get the first column value
                collection.Add(folder);
            }

            return collection;
        }


        public SForceAttachmentFolders GetDocumentFolders()
        {
            string query = "select f.Name, f.Id From Folder f  where f.Type='Document'";

            SForceAttachmentFolders collection = new SForceAttachmentFolders();
            QueryResult result = _sforce.queryAll(query);

            if (result.size == 0) return collection;

            for (int i = 0; i < result.records.Length; i++)
            {
                SForceAttachmentFolder folder = new SForceAttachmentFolder();
                folder.SForceObjectType = SForceObjectType.DocumentFolder;
                folder.Id = result.records[i].Id;
                folder.Name = result.records[i].Any[0].InnerText;  //get the first column value
                collection.Add(folder);
            }

            return collection;
            
        }

        


        /// <summary>
        /// returns a collection of products
        /// </summary>
        /// <returns></returns>
        public SForceAttachmentFolders getProducts()
        {
            string query = "Select a.Name, a.Id From Product2 a";
            return Folders(query, SForceObjectType.Product2);
        }

        /// <summary>
        /// returns a collection of campaigns
        /// </summary>
        /// <returns></returns>
        public SForceAttachmentFolders GetCampaigns()
        {
            string query = "Select a.Name, a.Id, a.Description From Campaign a where IsDeleted=false";
            return Folders(query, SForceObjectType.Campaign);
        }


        /// <summary>
        /// returns a collection of solutions
        /// </summary>
        /// <returns></returns>
        public SForceAttachmentFolders GetSolutions()
        {
            string query = "Select a.SolutionName, a.Id, a.SolutionNumber From Solution a where IsDeleted=false";
            return Folders(query,SForceObjectType.Solution);
        }


        /// <summary>
        /// returns a collection of accounts
        /// </summary>
        /// <returns></returns>
        public SForceAttachmentFolders getAccounts()
        {
            // a.AccountNumber
            string query = "Select a.Name, a.Id  From Account a where IsDeleted=false";
            return Folders(query, SForceObjectType.Account);
        }


        /// <summary>
        /// returns opportunities as a collection of SForceAttachmentFolders
        /// for the given account
        /// </summary>
        /// <param name="accountID"></param>
        /// <returns></returns>
        public SForceAttachmentFolders getOpportunitesForAccount(string accountID)
        {
            string query = "Select a.Name, a.Id From Opportunity a where a.AccountId='" + accountID + "'" ;
            return Folders(query,SForceObjectType.Opportunity);

        }

        /// <summary>
        /// returns opportunities as a collection of SForceAttachmentFolders
        /// for the given account
        /// </summary>
        /// <param name="accountID"></param>
        /// <returns></returns>
        public SForceAttachmentFolders GetOpportunitesForCampaign(string campaignID)
        {
            string query = "Select a.Name, a.Id From Opportunity a where a.CampaignId='" + campaignID + "'";
            return Folders(query, SForceObjectType.Opportunity);

        }

        /// <summary>
        /// returns contracts as a collection of SForceAttachmentFolders
        /// for the given account
        /// </summary>
        /// <param name="accountID"></param>
        /// <returns></returns>
        public SForceAttachmentFolders getContractsForAccount(string accountID)
        {
            string query = "Select a.ContractNumber, a.Id From Contract a where a.AccountId='" + accountID + "'";
            return Folders(query, SForceObjectType.Contact);

        }

        /// <summary>
        /// returns contacts as a collection of SForceAttachmentFolders
        /// for the given account
        /// </summary>
        /// <param name="accountID"></param>
        /// <returns></returns>
        public SForceAttachmentFolders getContactsForAccount(string accountID)
        {
            string query = "Select a.Name, a.Id From Contact a where a.AccountId='" + accountID + "'";
            return Folders(query, SForceObjectType.Contact);

        }

        /// <summary>
        /// returns a set of cases as SForceAttachmentFolders for the given
        /// account
        /// </summary>
        /// <param name="accountID"></param>
        /// <returns></returns>
        public SForceAttachmentFolders getCasesForAccount(string accountID)
        {
            string query = "Select a.CaseNumber, a.Id, a.Subject From Case a where a.AccountId='" + accountID + "'";
            SForceAttachmentFolders collection = new SForceAttachmentFolders();
            QueryResult result = _sforce.queryAll(query);

            if (result.size == 0) return collection;

            for (int i = 0; i < result.records.Length; i++)
            {
                SForceAttachmentFolder folder = new SForceAttachmentFolder();
                folder.SForceObjectType = SForceObjectType.Case;
                folder.Id = result.records[i].Id;
                folder.Name = result.records[i].Any[0].InnerText + "-" + result.records[i].Any[2].InnerText  ;  //get the first column value
                collection.Add(folder);
            }

            return collection;
        }

         /// <summary>
        /// returns a case as SForceAttachmentFolders for the given
        /// account
        /// </summary>
        /// <param name="accountID"></param>
        /// <returns></returns>
        public SForceAttachmentFolder GetCase(string caseID)
        {
            string query = "Select a.CaseNumber, a.Id, a.Subject From Case a where a.Id='" + caseID + "' and a.IsDeleted=false";
            QueryResult result = _sforce.queryAll(query);

            if (result.size == 0) return null;

            for (int i = 0; i < result.records.Length; i++)
            {
                SForceAttachmentFolder folder = new SForceAttachmentFolder();
                folder.SForceObjectType = SForceObjectType.Case;
                folder.Id = result.records[i].Id;
                folder.Name = result.records[i].Any[0].InnerText + "-" + result.records[i].Any[2].InnerText;  //get the first column value
                return folder;
            }
            return null;
        }
        
        /// <summary>
        /// returns cases in a collection of SForceAttachmentFolders for the given solution
        /// and contact
        /// </summary>
        /// <param name="solutionID"></param>
        /// <returns></returns>
        public SForceAttachmentFolders getCasesForSolutuion(string solutionID)
        {
            SForceAttachmentFolders collection = new SForceAttachmentFolders();
            string query = "Select c.CaseId from CaseSolution c where c.SolutionId='" + solutionID + "' and isDeleted=false";
            QueryResult result = _sforce.queryAll(query);
            if (result.size == 0) return collection;
            for (int i = 0; i < result.records.Length; i++)
            {
                string caseID = result.records[i].Any[0].InnerText;

                //get the case data
                SForceAttachmentFolder folder = GetCase(caseID);
                if (folder != null) collection.Add(folder);

            }
            return collection;

        }

        /// <summary>
        /// returns cases in a collection of SForceAttachmentFolders for the given account
        /// and contact
        /// </summary>
        /// <param name="accountID"></param>
        /// <param name="contactID"></param>
        /// <returns></returns>
        public SForceAttachmentFolders getCasesForAccountContact(string accountID, string contactID)
        {
            string query = "Select a.CaseNumber, a.Id, a.Subject From Case a where a.AccountId='" + accountID + "'  and a.ContactID='" + contactID + "'";
            SForceAttachmentFolders collection = new SForceAttachmentFolders();
            QueryResult result = _sforce.queryAll(query);

            if (result.size == 0) return collection;

            for (int i = 0; i < result.records.Length; i++)
            {
                SForceAttachmentFolder folder = new SForceAttachmentFolder();
                folder.SForceObjectType = SForceObjectType.Case;
                folder.Id = result.records[i].Id;
                folder.Name = result.records[i].Any[0].InnerText + "-" + result.records[i].Any[2].InnerText  ;  //get the first column value
                collection.Add(folder);
            }

            return collection;

        }

        /// <summary>
        /// returns a collection of users 
        /// </summary>
        /// <param name="folder"></param>
        /// <returns></returns>
        public SForceUsers GetUsers()
        {
            

            string query = "Select u.Username, u.Name, u.Id  From User u";

            SForceUsers collection = new SForceUsers();
            QueryResult result = _sforce.queryAll(query);

            if (result.size == 0) return collection;

            for (int i = 0; i < result.records.Length; i++)
            {
                SForceUser info = new SForceUser();
                info.UserID = result.records[i].Id;

                info.UserName = result.records[i].Any[0].InnerText;
                info.Name = result.records[i].Any[1].InnerText;

                collection.Add(info.UserID, info);
            }
            return collection;
        }

        /// <summary>
        /// returns a collection of the meta-data for attachments in a folder
        /// </summary>
        /// <param name="folder"></param>
        /// <returns></returns>
        public SForceAttachmentInfos GetAttachments(SForceAttachmentFolder folder)
        {
            if (folder == null) return null;

            string query ="Select a.CreatedDate, a.LastModifiedDate, a.SystemModstamp, a.ParentId, a.Name, a.Id, a.ContentType, a.BodyLength, a.OwnerID, a.LastModifiedByID,a.CreatedByID  From Attachment a" +
                  " Where a.parentId='" + folder.Id + "'";

            SForceAttachmentInfos collection = new SForceAttachmentInfos();
            QueryResult result = _sforce.queryAll(query);

            if (result.size == 0) return collection;
       
            for (int i = 0; i < result.records.Length; i++)
            {
                SForceAttachmentInfo info = new SForceAttachmentInfo();
                info.Id=result.records[i].Id;

                DateTime tempCreated = new DateTime();
                if (DateTime.TryParse(result.records[i].Any[0].InnerText, out tempCreated))
                {
                    info.CreatedDate = tempCreated;
                }

                DateTime temp = new DateTime();
                if (DateTime.TryParse(result.records[i].Any[1].InnerText, out temp))
                {
                    info.LastModifiedDate = temp;
                }


                DateTime tempSystemModified = new DateTime();
                if (DateTime.TryParse(result.records[i].Any[2].InnerText, out tempSystemModified))
                {
                    info.SystemModifiedDate = tempSystemModified;
                }
                
                info.ParentId=result.records[i].Any[3].InnerText;  //parentID
                info.Name=result.records[i].Any[4].InnerText;  //Name
                info.Type=result.records[i].Any[6].InnerText;  //type
                info.Size=long.Parse(result.records[i].Any[7].InnerText);
                info.OwnerUserID = result.records[i].Any[8].InnerText;
                info.ModifiedUserID = result.records[i].Any[9].InnerText;
                info.CreatedUserID = result.records[i].Any[10].InnerText; 
                collection.Add(info);
            }
            return collection;
        }




        public SForceAttachmentInfos GetDocuments(SForceAttachmentFolder folder)
        {


            string query = "Select d.CreatedDate, d.LastModifiedDate,d.SystemModstamp,d.FolderID,d.Name, d.Id, d.ContentType, d.BodyLength,  d.AuthorId, d.LastModifiedById, d.CreatedById From Document d where d.FolderId='" + folder.Id + "'";

            SForceAttachmentInfos collection = new SForceAttachmentInfos();
            QueryResult result = _sforce.queryAll(query);

            if (result.size == 0) return collection;

            for (int i = 0; i < result.records.Length; i++)
            {
                SForceAttachmentInfo info = new SForceAttachmentInfo();

                info.ParentType = SForceObjectType.DocumentFolder;
                info.Id = result.records[i].Id;

                DateTime tempCreated = new DateTime();
                if (DateTime.TryParse(result.records[i].Any[0].InnerText, out tempCreated))
                {
                    info.CreatedDate = tempCreated;
                }

                DateTime temp = new DateTime();
                if (DateTime.TryParse(result.records[i].Any[1].InnerText, out temp))
                {
                    info.LastModifiedDate = temp;
                }


                DateTime tempSystemModified = new DateTime();
                if (DateTime.TryParse(result.records[i].Any[2].InnerText, out tempSystemModified))
                {
                    info.SystemModifiedDate = tempSystemModified;
                }

                info.ParentId = result.records[i].Any[3].InnerText;  //parentID
                info.Name = result.records[i].Any[4].InnerText;  //Name
                info.Type = result.records[i].Any[6].InnerText;  //type
                info.Size = long.Parse(result.records[i].Any[7].InnerText);
                info.OwnerUserID = result.records[i].Any[8].InnerText;
                info.ModifiedUserID = result.records[i].Any[9].InnerText;
                info.CreatedUserID = result.records[i].Any[10].InnerText;
                collection.Add(info);
            }
            return collection;
        }

        /// <summary>
        /// returns the contents of an attachment
        /// </summary>
        /// <param name="info"></param>
        /// <returns></returns>
        public byte[] GetAttachment(SForceAttachmentInfo info)
        {
            string query = string.Empty;
            if (info.ParentType == SForceObjectType.DocumentFolder)
            {
                query = "Select a.Body From Document a Where a.Id='" + info.Id + "'";
            }
            else
            {
                query = "Select a.Body From Attachment a  Where a.Id='" + info.Id + "'";
            }

            byte[] data = null;
            QueryResult result = _sforce.queryAll(query);

            if (result.size == 0) return data;

            for (int i = 0; i < result.records.Length; i++)
            {
                data = new byte[info.Size];
                data = Convert.FromBase64String(result.records[i].Any[0].InnerText);
                
                 
            }
            return data;
        }

        /// <summary>
        /// Creates a SForceAttachmentFolder object which does not have
        /// a corrosponding ID in SalesForce
        /// </summary>
        /// <param name="groupType"></param>
        /// <returns></returns>
        public SForceAttachmentFolder CreateGroupingFolder(SForceObjectType groupType)
        {
            SForceAttachmentFolder folder = new SForceAttachmentFolder();
            folder.SForceObjectType = SForceObjectType.Group_Only;
            folder.GroupType = groupType;
            folder.Id = null;
            folder.Name = null;

            return folder;
        }



    }
}
